using System;
using System.Collections.Generic;
using UnityEngine;

namespace BF
{
    public class BasePool<T> : IPool<T>, IPool where T : class, IRecycleable
    {
        /// <summary>
        /// Item放入池中后最少需要0.02s才能再次取出使用
        /// </summary>
        protected virtual float ITEM_FREEZE_TIME => 0.02f;

        /// <summary>
        /// 对象创建器
        /// </summary>
        protected ICreator<T> _creator;
        /// <summary>
        /// 对象池缓存
        /// </summary>
        protected Queue<T> _cache = new Queue<T>();

        /// <summary>
        /// 当前时间，用于判断ItemCD
        /// </summary>
        private float curTime => MonoPoolRoot.instance.time;
        /// <summary>
        /// 对象池名字
        /// </summary>
        public readonly string tName;

        public BasePool()
        {
            this.tName = typeof(T).Name;
        }

        public BasePool<T> Init()
        {
            if (_creator == null)
            {
                _creator = new SimpleCreator<T>();
            }
            return this;
        }

        public virtual BasePool<T> Init(Func<T> createFunc)
        {
            if (_creator == null)
            {
                _creator = new SimpleCreator<T>(createFunc);
            }
            return this;
        }

        /// <summary>
        /// 先准备一定数量的对象
        /// </summary>
        public BasePool<T> Prepare(int count)
        {
            List<T> list = new List<T>();
            for (int i = 0; i < count; ++i)
            {
                list.Add(Pop());
            }
            foreach (T t in list)
            {
                t.ReturnToPool();
            }
            list.Clear();
            return this;
        }

        object IPool.Pop()
        {
            return this.Pop();
        }

        bool IPool.Push(object item)
        {
            return this.Push(item as T);
        }

        /// <summary>
        /// 将对象从池中取出
        /// </summary>
        public virtual T Pop()
        {
            if (_creator == null)
            {
                Init();
            }

            T item = PopFromCache();
            if (item == null)
            {
                item = _creator.Create();
            }
            item.pool = this;
            item.isRecycled = false;

            if (!item.isFirstShow)
            {
                item.isFirstShow = true;
                item.OnFirstShow();
            }
            item.OnShow();

            OnItemShow(item);

            return item;
        }

        protected virtual T PopFromCache()
        {
            while (_cache.Count > 0)
            {
                T temp = _cache.Peek();
                if (temp == null)
                {
                    _cache.Dequeue();
                    Log("Pop cache error, item is null");
                }
                else if (temp.recycleTime + ITEM_FREEZE_TIME > curTime)
                {
                    return null;
                }
                else
                {
                    return _cache.Dequeue();
                }
            }
            return null;
        }


        /// <summary>
        /// 将对象放回池中
        /// </summary>
        public bool Push(T item)
        {
            if (item == null)
            {
                Log("Recycle Error: Item is null");

                return false;
            }

            if (item.isRecycled)
            {
                Log("Recycle Error: Item is Recycled");
#if DEBUG
                if (item is Timer t)
                {
                    Log($"TimerFrom {t.GetHashCode()}:\n{t.popStackTrace}");
                }
#endif
                return false;
            }

            item.pool = null;
            item.isRecycled = true;
            item.recycleTime = curTime;
            item.OnRecycle();
            OnItemRecycle(item);

            _cache.Enqueue(item);

            return true;
        }

        protected virtual void OnItemShow(T item)
        {

        }

        protected virtual void OnItemRecycle(T item)
        {
            
        }

        /// <summary>
        /// 删除池中所有缓存对象
        /// </summary>
        public void DestroyAllItemCache()
        {
            _cache.ForEach(it => it?.Destroy());
            _cache.Clear();
        }


        [System.Diagnostics.Conditional("DEBUG")]
        private void Log(string info)
        {
            UnityEngine.Debug.Log($"[Pool][{tName}] {info}");
        }

        public virtual void Dispose()
        {
            DestroyAllItemCache();
            _creator = null;
        }
    }
}
